Creating & Formatting Tables

Data tables are a form of visualization!

The same principles apply to tables!

  • Clear titles
  • Mindful arrangement
  • Don’t make people tilt their head!

You can be creative with tables!

A simple table

evals %>% 
  rename(sex = gender, 
         minority_status = ethnicity) %>% 
  group_by(sex, minority_status) %>% 
  summarize(mean_eval = mean(score))
# A tibble: 4 × 3
# Groups:   sex [2]
  sex    minority_status mean_eval
  <fct>  <fct>               <dbl>
1 female minority             3.93
2 female not minority         4.13
3 male   minority             4.25
4 male   not minority         4.23

Tools for spicing up your table

Step 1: Get an orientation you want

This is a great place to showcase your pivot_wider() skills!

evals %>% 
  rename(sex = gender, 
         minority_status = ethnicity) %>% 
  group_by(sex, minority_status) %>% 
  summarize(mean_eval = mean(score), 
            .groups = "drop") %>% 
  pivot_wider(names_from = sex, 
              values_from = mean_eval)
# A tibble: 2 × 3
  minority_status female  male
  <fct>            <dbl> <dbl>
1 minority          3.93  4.25
2 not minority      4.13  4.23

Step 2: Getting a nicer rendered table

Some options:

  • The kable() function from the knitr package
  • The kableExtra package
  • The gt package

The kable() function

my_table %>% 
  knitr::kable(format = "html", 
               digits = 3, 
               col.names = 
                 c("Minority Status", 
                   "Female Faculty", 
                   "Male Faculty"),
               caption = "Mean evaluation scores for a sample of 94 UT Austin professors")


Note: You can also use Quarto options (tbl-cap and tbl-cap-location) to include a caption and choose where the caption prints!

Mean evaluation scores for a sample of 94 UT Austin professors
Minority Status Female Faculty Male Faculty
minority 3.933 4.250
not minority 4.129 4.232

The kableExtra package

my_table %>% 
  knitr::kable(format = "html", 
               digits = 3, 
               col.names = 
                 c("Minority Status", 
                   "Female Faculty", 
                   "Male Faculty"),
               caption = "Mean evaluation scores for a sample of 94 UT Austin professors") %>% 
  kableExtra::kable_styling(bootstrap_options = "striped", 
                            font_size = 28)
Mean evaluation scores for a sample of 94 UT Austin professors
Minority Status Female Faculty Male Faculty
minority 3.933 4.250
not minority 4.129 4.232

Additional themes

my_table %>% 
  knitr::kable(format = "html", 
               digits = 3, 
               col.names = 
                 c("Minority Status", 
                   "Female Faculty", 
                   "Male Faculty"),
               caption = "Mean evaluation scores for a sample of 94 UT Austin professors") %>% 
  kableExtra::kable_minimal(html_font = "Arial")
Mean evaluation scores for a sample of 94 UT Austin professors
Minority Status Female Faculty Male Faculty
minority 3.933 4.250
not minority 4.129 4.232
my_table %>% 
  knitr::kable(format = "html", 
               digits = 3, 
               col.names = 
                 c("Minority Status", 
                   "Female Faculty", 
                   "Male Faculty"),
               caption = "Mean evaluation scores for a sample of 94 UT Austin professors") %>% 
  kableExtra::kable_classic(html_font = "Arial")
Mean evaluation scores for a sample of 94 UT Austin professors
Minority Status Female Faculty Male Faculty
minority 3.933 4.250
not minority 4.129 4.232

The gt package

Working with gt

my_table %>% 
  gt()
minority_status female male
minority 3.933333 4.2500
not minority 4.128931 4.2325

Changing column names

my_table %>% 
  gt() %>% 
  cols_label(minority_status = "Minority Group", 
             female = "Female Faculty", 
             male = "Male Faculty")
Minority Group Female Faculty Male Faculty
minority 3.933333 4.2500
not minority 4.128931 4.2325


Note: You can also use the md() function to specify Markdown formatting (e.g., italics or boldface) within the column labels (e.g., ethnicity = md("**Minority Group**")).

Adding a table header and / or subheader

samp_size <- nrow(evals)

my_table %>% 
  gt() %>% 
  cols_label(minority_status = "Minority Group", 
             female = "Female Faculty", 
             male = "Male Faculty") %>% 
  tab_header(title = "Mean Evaluation Scores",
             subtitle = glue("for {samp_size} faculty at UT Austin")
             )

Mean Evaluation Scores
for 463 faculty at UT Austin
Minority Group Female Faculty Male Faculty
minority 3.933333 4.2500
not minority 4.128931 4.2325

Formatting Values

my_table %>% 
  gt() %>% 
    cols_label(minority_status = "Minority Group", 
             female = "Female Faculty", 
             male = "Male Faculty") %>% 
  tab_header(title = "Mean Evaluation Scores",
             subtitle = glue("for {samp_size} faculty at UT Austin")
             ) %>% 
  fmt_number(columns = 2:3, decimals = 3)

Mean Evaluation Scores
for 463 faculty at UT Austin
Minority Group Female Faculty Male Faculty
minority 3.933 4.250
not minority 4.129 4.232

A table with percentages

evals %>% 
  count(sex, minority_status) %>% 
  group_by(sex) %>% 
  mutate(prop = n / sum(n)
         ) 
# A tibble: 4 × 4
# Groups:   sex [2]
  sex    minority_status     n  prop
  <fct>  <fct>           <int> <dbl>
1 female minority           36 0.185
2 female not minority      159 0.815
3 male   minority           28 0.104
4 male   not minority      240 0.896
evals %>% 
  count(sex, minority_status) %>% 
  group_by(sex) %>% 
  mutate(prop = n / sum(n)
         ) %>% 
  select(-n) %>% 
  pivot_wider(names_from = sex, 
              values_from = prop)
# A tibble: 2 × 3
  minority_status female  male
  <fct>            <dbl> <dbl>
1 minority         0.185 0.104
2 not minority     0.815 0.896

Formatting percentages

my_percent_table %>% 
  gt() %>% 
  fmt_percent(columns = 2:3, decimals = 2)
minority_status female male
minority 18.46% 10.45%
not minority 81.54% 89.55%

Interactive Tables with DT

DT::datatable(evals)